#!/bin/sh

resource_watch() {
  local FILTERED_KIND
  local FILTERED_NAME
  local KIND
  local NAMESPACE
  local OWNER_KIND
  local LOG_IN_FILES=false
  local LOG_IN_PATH="$TARGET_PATH/resource-watch"
  local KINDS
  local KIND_PID
  local KIND_PIDS
  local ALL_KIND_PIDS
  local EXISTING_KIND_PID
  local KIND_PID_PATH
  local RUNNING_KIND_PIDS
  local EXCLUDED_FILTERED_KIND
  local FOLLOW=false
  EXCLUDED_FILTERED_KIND="^\(bindings\|componentstatuses"
  EXCLUDED_FILTERED_KIND="$EXCLUDED_FILTERED_KIND\|localsubjectaccessreviews\.authorization\.k8s\.io"
  EXCLUDED_FILTERED_KIND="$EXCLUDED_FILTERED_KIND\|selfsubjectaccessreviews\.authorization\.k8s\.io"
  EXCLUDED_FILTERED_KIND="$EXCLUDED_FILTERED_KIND\|selfsubjectrulesreviews\.authorization\.k8s\.io"
  EXCLUDED_FILTERED_KIND="$EXCLUDED_FILTERED_KIND\|subjectaccessreviews\.authorization\.k8s\.io"
  EXCLUDED_FILTERED_KIND="$EXCLUDED_FILTERED_KIND\|tokenreviews\.authentication\.k8s\.io"
  EXCLUDED_FILTERED_KIND="$EXCLUDED_FILTERED_KIND\)$"
  while [ "$#" -gt 0 ]
  do
    case "$1" in
      -n|--namespace)
        shift
        NAMESPACE="$1"
        shift
        ;;
      -k|--kind)
        shift
        FILTERED_KIND="$1"
        shift
        ;;
      --name)
        shift
        FILTERED_NAME="$1"
        shift
        ;;
      -F|--log-in-files)
        shift
        LOG_IN_FILES=true
        ;;
      -P|--log-in-path)
        shift
        LOG_IN_PATH="$1"
        shift
        ;;
      -f|--follow)
        shift
        FOLLOW="true"
        ;;
      *)
        echo >&2 "Unknown parameter $1 (use: --namespace <namespace>; --kind <kind>; --name <name>)"
        return 1
        ;;
    esac
  done
  KIND_PIDS=""
  while true
  do
    RUNNING_KIND_PIDS=""
    for KIND_PID in $KIND_PIDS
    do
      KIND="${KIND_PID%:*}"
      if [ -z "${KIND_PID#*:}" ] || ! kill -0 "${KIND_PID#*:}" >/dev/null 2>&1
      then
        if [ "$FOLLOW" = true ]
        then
          echo "Start watching $KIND..."
        fi
        KIND_PID_PATH="$TARGET_PATH/resource-$KIND-watch.pid"
        resource_kind_watch_in_trap -k "$KIND" -p "$KIND_PID_PATH" \
          $([ -z "$NAMESPACE" ] || printf '%s %s' -n "$NAMESPACE") \
          $([ "$LOG_IN_FILES" != true ] || printf %s '-F') -P "$LOG_IN_PATH" \
          $([ -z "$FILTERED_NAME" ] || printf '%s %s' --name "$FILTERED_NAME") \
          $(if [ "$FOLLOW" = true ]; then printf %s -f; fi)
        KIND_PID="$KIND:$(cat "$KIND_PID_PATH")"
      fi
      RUNNING_KIND_PIDS="$RUNNING_KIND_PIDS $KIND_PID"
    done
    if [ -n "$RUNNING_KIND_PIDS" ]
    then
      if [ "$FOLLOW" != true ]
      then
        break
      fi
      sleep 10
    fi
    KIND_PIDS="$RUNNING_KIND_PIDS"
    ALL_KIND_PIDS="$(kubectl api-resources -o name \
      | grep -v "$EXCLUDED_FILTERED_KIND" \
      | ( [ -z "$FILTERED_KIND" ] && cat || grep -xF "$FILTERED_KIND" ) \
      | sed 's/^\(.*\)$/\1/')"
    for KIND_PID in $ALL_KIND_PIDS
    do
      if ! echo "$KIND_PIDS" | tr ' ' '\n' | grep -v '$^' | cut -d : -f 1 | grep -qxF "$KIND_PID"
      then
        KIND_PIDS="$KIND_PIDS $KIND_PID:"
      fi
    done
  done
}

resource_kind_watch_in_trap() {
  local FILTERED_NAME
  local KIND
  local NAMESPACE
  local OWNER_KIND
  local LOG_IN_FILES=false
  local LOG_IN_PATH="$TARGET_PATH/resource-watch"
  local KINDS
  local KIND_PID
  local KIND_PIDS
  local KIND_PID_PATH
  local FOLLOW=false
  while [ "$#" -gt 0 ]
  do
    case "$1" in
      -n|--namespace)
        shift
        NAMESPACE="$1"
        shift
        ;;
      -k|--kind)
        shift
        KIND="$1"
        KIND_PID_PATH="$TARGET_PATH/resource-$KIND-watch.pid"
        shift
        ;;
      -p|--kind-pid-path)
        shift
        KIND_PID_PATH="$1"
        shift
        ;;
      --name)
        shift
        FILTERED_NAME="$1"
        shift
        ;;
      -F|--log-in-files)
        shift
        LOG_IN_FILES=true
        ;;
      -P|--log-in-path)
        shift
        LOG_IN_PATH="$1"
        shift
        ;;
      -f|--follow)
        shift
        FOLLOW="true"
        ;;
      *)
        echo >&2 "Unknown parameter $1 (use: --namespace <namespace>; --kind <kind>; --name <name>)"
        return 1
        ;;
    esac
  done
  local JQ_QUERY="$(if [ "$FOLLOW" != true ]; then printf '.items[]'; else printf '.'; fi)"
  if [ -n "$FILTERED_NAME" ]
  then
    JQ_QUERY="$JQ_QUERY|select(.metadata.name|test($FILTERED_NAME))"
  fi
  trap_exec kubectl get "$KIND" \
      $(if [ -z "$NAMESPACE" ]; then echo '--all-namespaces'; else echo '-n '"$NAMESPACE"; fi) \
      -o json \
      $(if [ "$FOLLOW" = true ]; then printf %s --watch-only; fi) \
    | jq --unbuffered -c "$JQ_QUERY|@base64" \
    | {
      set +x
      while IFS="$(printf '\n')" read -r RESOURCE
      do
        echo "$RESOURCE" | jq -r '@base64d' | jq -r '.metadata.name + " " + .metadata.namespace' \
          | while read -r NAME NAMESPACE
            do
              if "$LOG_IN_FILES"
              then
                mkdir -p "$LOG_IN_PATH/$NAMESPACE/$KIND"
                printf %s "$RESOURCE" | jq -r '@base64d' | jq . >> "$LOG_IN_PATH/$NAMESPACE/$KIND/$NAME.log" || true
              else
                printf %s "$RESOURCE" | jq -r '@base64d' | jq . || true
              fi
            done
      done
      } &
  printf %s "$!" > "$KIND_PID_PATH"
}